"use strict";

import Vue from "vue";
import axios from "axios";
import dbl from "@/utils/dbl";
import store from "../store";
import { Notification, MessageBox, Message } from "element-ui";
import qs from "qs";
import router from "@/router";

let config = {
	// baseURL: conf.baseURL,
	timeout: 60 * 1000 * 2 // Timeout
	// withCredentials: true, // Check cross-site Access-Control
};

let reqList = [];

/**
 * 阻止重复请求
 * @param {array} reqList - 请求缓存列表
 * @param {string} url - 当前请求地址
 * @param {function} cancel - 请求中断函数
 * @param {string} errorMessage - 请求中断时需要显示的错误信息
 */
const stopRepeatRequest = function(reqList, url, cancel, errorMessage) {
	const errorMsg = errorMessage || "";
	for (let i = 0; i < reqList.length; i++) {
		if (reqList[i] === url) {
			cancel(errorMsg);
			return;
		}
	}
	reqList.push(url);
};

/**
 * 允许某个请求可以继续进行
 * @param {array} reqList 全部请求列表
 * @param {string} url 请求地址
 */
const allowRequest = function(reqList, url) {
	for (let i = 0; i < reqList.length; i++) {
		if (reqList[i] === url) {
			reqList.splice(i, 1);
			break;
		}
	}
};

const errorMsg = error => {
	Message({
		customClass: "systemMessage",
		duration: "10000",
		showClose: true,
		message: error && error.length <= 100 ? error : "系统错误，请联系管理员",
		type: "error"
	});
};

let is401 = false;

const _axios = axios.create(config);

_axios.interceptors.request.use(
	async config => {
		let cancel;
		// 设置cancelToken对象
		config.cancelToken = new axios.CancelToken(function(c) {
			cancel = c;
		});
		// 阻止重复请求。当上个请求未完成时，相同的请求不会进行
		//config.method === 'post' && stopRepeatRequest(reqList, config.url, cancel, `${config.url} 请求被中断`)

		let token = dbl.get("token");
		let url = config.url;
		if (token && url !== "/auth/code" && url !== "/auth/login") {
			config.headers["Authorization"] = token;
		} else {
			delete config.headers["Authorization"];
		}

		if (config.method === "get") {
			config.paramsSerializer = function(params) {
				return qs.stringify(params, { arrayFormat: "repeat" });
			};
			config.data = qs.stringify(config.data);
		}

		// 这里加这个判断，主要是为了在get请求下，可以穿json
		config.headers["Content-Type"] = config.formData
			? "application/x-www-form-urlencoded"
			: "application/json";
		return config;
	},
	async error => {
		// Do something with request error
		return Promise.reject(error);
	}
);

// Add a response interceptor
_axios.interceptors.response.use(
	function(response) {
		// 增加延迟，相同请求不得在短时间内重复发送
		response.config.methods == "post" &&
			setTimeout(() => {
				allowRequest(reqList, response.config.url);
			}, 1000);

		const code = response.status;
		if (code < 200 || code > 300) {
			errorMsg(response.data.msg);
			return Promise.reject("error");
		} else {
			if (response.data.code === 1) {
				errorMsg(response.data.msg);
			} else {
				return response;
			}
		}
	},
	function(error) {
		Message.closeAll();
		if (axios.isCancel(error)) {
			console.log(error);
		} else {
			// 增加延迟，相同请求不得在短时间内重复发送
			//setTimeout(() => { allowRequest(reqList, error.config.url)}, 1000)
		}

		let code = error.response ? error.response.status : "";

		if (error.toString().indexOf("Error: timeout") !== -1) {
			errorMsg("网络请求超时");
			return Promise.reject(error);
		}

		if ([401].includes(code)) {
			let currentRoute = router.currentRoute.path;
			currentRoute == "/login" && (is401 = true);
			if (!is401) {
				is401 = true;
				MessageBox.alert(
					"登录状态已过期，您可以继续留在该页面，或者重新登录",
					"系统提示",
					{
						confirmButtonText: "重新登录",
						cancelButtonText: "取消",
						type: "warning"
					}
				)
					.then(() => {
						//缓存掉线前最后的页面，登录后优先跳转
						localStorage.setItem(
							"lastUrl",
							window.location.pathname + window.location.search
						);
						store.dispatch("LogOut");
					})
					.catch(() => {
						is401 = false;
					});
			}
		} else if (code == 403) {
			router.replace("/error403");
		} else {
			errorMsg(error.response ? error.response.data.msg : "");
		}
		return Promise.reject(error);
	}
);

Plugin.install = function(Vue) {
	Vue.axios = _axios;
	Object.defineProperties(Vue.prototype, {
		axios: {
			get() {
				return _axios;
			}
		}
	});
};

Vue.use(Plugin);

export default _axios;
